#ifndef TREEGEN_H
#define TREEGEN_H
#include "common.h"
#include "vector"
#include "renderer.h"
#include <QFile>
#include <QTextStream>
#include "barkgen.h"
#include <vector>
using namespace std;


class Shadow2D;

enum Fate{FLOWER, METAMER, DORMANT, ABORT};


//Bud is same as node
struct BarkStruct;
struct Bud{
    //To make pine trees or something like that, you need to abort buds if they do not grow for n number of seasons.
    Fate term_fate, aux_fate;
    int budsAbove;
    float exposure;
    float darken;
    float rotleaf;
    int season;
    //unit vector in direction internode is pointing
    float3 direction;
    //pertain to internode below node
    float diameter;
    float length;
    //the angle at which the internode is relative to the axis. Theta is defined to be PI/2 at verticle.
    //(For 2D)
    float phi;
    float theta;
    //refer to start and end positions of internode below this one
    float3 start;
    float3 end;
    bool leaf;
    int i,j,k; //shadow prop voxel coordinates, where the tree root is 0,0,0
    //refer to terminal and auxilary buds. If NULL, that means this node has a bud of that type
    //here, otherwise it means that bud has already grown and there is a child node.
    Bud *term, *aux; // remember to set these to NULL at construction
    //Q resource for terminal and auxBuds, and internode
    float tQ, aQ, iQ;
    //resource:
    float resource, ares, tres;

    float auxAngle;
    float3 auxDir;
    //direction of optimum growth for auxilery and terminal buds
    float3 tV, aV;
    int spaceColIndex; // Diem: each bud is associated with a unique index.
    vector<double*> assocMarkers;
    vector<double*> auxMarkers;
    vector<double*> termMarkers;
    BarkStruct the_bark;
    int branchID;
    Bud *parent;
    Bud(){//TODO: finish constructor
        term = NULL;
        aux = NULL;
        term_fate = DORMANT;
        aux_fate = DORMANT;
        budsAbove = 0;
        exposure =0;
        darken =0;;
        season =0;;
        direction = float3(0,0,0);
        diameter = 0;
        length = 0;
        phi = 0;
        theta = 0;
        start = float3(0,0,0);
        end= float3(0,0,0);;
        leaf = true;
        i = 0;
        j = 0;
        k = 0;
        tQ = 0;
        aQ = 0;
        iQ = 0;
        resource = 0;
        ares = 0;
        tres =0;
        auxAngle = 0;
        auxDir = float3(0,0,0);
        tV = float3(0,0,0);
        aV = float3(0,0,0);
        spaceColIndex = 0;
        rotleaf = 0;
    }
};

struct Branch{
    vector<Branch*> children;
    bool just_bud;
    bool bud_is_aux;
    int numbuds;
    Bud *bud, *startBud;
    Branch *tBranch;
    float Q;
    float resource;
    float ratio;
    float w;
    int numinternodes;
    Branch(){
        children = vector<Branch*>();
        just_bud = false;
        bud_is_aux = false;
        numbuds = 0;
        bud = NULL;
        Q = 0;
        ratio = 0;
        resource =0;
        numinternodes =1;
        tBranch =NULL;
    }

    bool operator<(const Branch &rhs) const{
        return ratio < rhs.ratio;
    }
    bool operator>(const Branch &rhs) const{
        return ratio > rhs.ratio;
    }
};


class TreeGen
{
public:
    TreeGen();
    ~TreeGen();
    Bud *treeRoot;
    int branchIdGen;
    void freeTree(Bud *root);
    virtual void calculateBranchDiameter(Bud *b) = 0;

    void saveTreeToEvanFormat();
    void recurSave(Bud *bud, int parentindx, QTextStream &out);
    vector <float *> treeToArray();
    void toArrayRecur(vector <float *> & v, Bud * bud, int index, int & arrLength);
    vector <float*> readFromFile( QString name);
    bool writeToFile(vector <float*> v, QString name);

    bool saveTreeToFile( QString filename);

    void TreeToEvanFormat();
    void BSave();

    QFile *m_out;
    int m_nextIndx;
    bool in_interact;
    bool m_addMultMeta;
    bool m_apicalControl;
    bool m_useBH;
    BarkGen barkGenerator;
float LAMBDA;
//alpha modifies resource at base
float ALPHA;
//determines rate of diameter growth (smaller the fatter)
float DIAMETER_RATE;
// >0 for growth influenced up, <0 for growth skewed down
float TROPISM;
//default angle of auxilary branch
float AUX_ANGLE;
//weight of default aux direction in branch growth
float AUX_WEIGHT;
//weight of default term direction in branch growth
float TERM_WEIGHT;
//scale adujst for term and aux directions
float TLENGTH;
float ALENGTH;
float SHED_THRES;
float W_MAX;
float W_MIN;
float KAPPA;
int numBuds;
int m_apicalDepth;

protected:
    void basipetalBH(Bud *b);
    void passBH(bool shed);
    void passPriority(bool shed);
    void gatherP(Bud *b, Branch *cur);
    void distributeP(Branch *cur, int depth);

    void pass2BH(Bud *b);
    void createBudFromBud(Bud *b, Bud *out);
    virtual void initializeBud(Bud *b) = 0;
    float3 _tropism, _wind;
    void produceShootsOld(Bud *b);
    //depth refers to branch depth, ie only increment depth is moving to auxilary bud;
    void produceShootsNew(Bud *b, int depth);


    //only to be used with shadow propogation
    void shedBranches(Bud *b);
    void shedBranchesWithPriority(Branch *b);
    void clearBranches(Branch *b);


};

#endif // TREEGEN_H
